package middleware

import (
	"autoDeploy/config"
	"autoDeploy/utils/token"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt"
	"net/http"
	"strconv"
)

// ParseToken 函数解析 JWT Token 并返回所有的 Claims 信息
func ParseToken(tokenString string) (jwt.MapClaims, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// 确保 Token 使用了正确的签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(config.SecretKey), nil
	})
	if err != nil {
		return nil, err
	}
	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		return claims, nil
	}
	return nil, fmt.Errorf("invalid token")
}

// AuthMiddleware 鉴权中间件 解析 token 中的数据
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 从请求中获取 Token
		tokenString := c.GetHeader("token")
		if tokenString == "" {
			tokenString = c.Query("token") // 如果没有在头部，尝试从查询参数获取
		}
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "请求未携带token，无权限访问",
			})
			c.Abort()
			return
		}

		// 2. 解析 Token，获取所有 Claims 信息
		claims, err := ParseToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "无效的token",
			})
			c.Abort()
			return
		}
		// 使用角色id判断是否是普通用户
		roleID, ok := claims["role_id"].(float64)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "非法token，Token中缺少角色id",
			})
			c.Abort()
			return
		}
		if roleID != 2 {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "无权访问",
			})
			c.Abort()
			return
		}

		// 3. 使用用户id调用 GetToken 方法，判断 Redis 中是否有 Token
		userID, ok := claims["user_id"].(float64)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "Token中缺少用户id",
			})
			c.Abort()
			return
		}
		userIDStr := strconv.FormatFloat(userID, 'f', 0, 64)

		redisToken, err := token.GetToken(userIDStr)

		if err != nil {
			if redisToken == "0" {
				c.JSON(http.StatusUnauthorized, gin.H{
					"code": http.StatusUnauthorized,
					"msg":  "Token已过期或无效",
				})
				c.Abort()
				return
			} else {
				c.JSON(http.StatusInternalServerError, gin.H{
					"code": http.StatusInternalServerError,
					"msg":  "服务器内部错误",
				})
				c.Abort()
				return
			}
		}

		// 4. 鉴权成功，将 Claims 信息存储在上下文中，供后续使用
		c.Set("claims", claims) // 存储所有的 Claims 信息
		c.Next()
	}
}

// AdminAuthMiddleware 管理员鉴权中间件
func AdminAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 从请求中获取 Token
		tokenString := c.GetHeader("token")
		if tokenString == "" {
			tokenString = c.Query("token") // 如果没有在头部，尝试从查询参数获取
		}
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "请求未携带token，无权限访问",
			})
			c.Abort()
			return
		}

		// 2. 解析 Token，获取所有 Claims 信息
		claims, err := ParseToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "无效的token",
			})
			c.Abort()
			return
		}

		// 使用角色id判断是否是管理员
		roleID, ok := claims["role_id"].(float64)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "非法token，Token中缺少角色id",
			})
			c.Abort()
			return
		}
		if roleID != 1 {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "非管理员，无权访问",
			})
			c.Abort()
			return
		}

		// 3. 使用用户id调用 GetToken 方法，判断 Redis 中是否有 Token
		userID, ok := claims["user_id"].(float64)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "Token中缺少用户id",
			})
			c.Abort()
			return
		}
		userIDStr := strconv.FormatFloat(userID, 'f', 0, 64)

		redisToken, err := token.GetToken(userIDStr)

		if err != nil {
			if redisToken == "0" {
				c.JSON(http.StatusUnauthorized, gin.H{
					"code": http.StatusUnauthorized,
					"msg":  "Token已过期或无效",
				})
				c.Abort()
				return
			} else {
				c.JSON(http.StatusInternalServerError, gin.H{
					"code": http.StatusInternalServerError,
					"msg":  "服务器内部错误",
				})
				c.Abort()
				return
			}
		}

		// 4. 鉴权成功，将 Claims 信息存储在上下文中，供后续使用
		c.Set("claims", claims) // 存储所有的 Claims 信息
		c.Next()
	}
}

// RouterAuthMiddleware 鉴权中间件 解析 token 中的数据
func RouterAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 1. 从请求中获取 Token
		tokenString := c.GetHeader("token")
		if tokenString == "" {
			tokenString = c.Query("token") // 如果没有在头部，尝试从查询参数获取
		}
		if tokenString == "" {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "请求未携带token，无权限访问",
			})
			c.Abort()
			return
		}

		// 2. 解析 Token，获取所有 Claims 信息
		claims, err := ParseToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "无效的token",
			})
			c.Abort()
			return
		}

		// 3. 使用用户id调用 GetToken 方法，判断 Redis 中是否有 Token
		userID, ok := claims["user_id"].(float64)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{
				"code": http.StatusUnauthorized,
				"msg":  "Token中缺少用户id",
			})
			c.Abort()
			return
		}
		userIDStr := strconv.FormatFloat(userID, 'f', 0, 64)

		redisToken, err := token.GetToken(userIDStr)

		if err != nil {
			if redisToken == "0" {
				c.JSON(http.StatusUnauthorized, gin.H{
					"code": http.StatusUnauthorized,
					"msg":  "Token已过期或无效",
				})
				c.Abort()
				return
			} else {
				c.JSON(http.StatusInternalServerError, gin.H{
					"code": http.StatusInternalServerError,
					"msg":  "服务器内部错误",
				})
				c.Abort()
				return
			}
		}

		// 4. 鉴权成功，将 Claims 信息存储在上下文中，供后续使用
		c.Set("claims", claims) // 存储所有的 Claims 信息
		c.Next()
	}
}
